#pragma once
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/wait.h>

#include<pthread.h>
#include<cstdlib>
#include<cstring>
#include<string>
#include<functional>

#include"log.hpp"
#include"inetaddr.hpp"
#include"threadpool.hpp"

#define DIE(code) exit(code)
#define CONV(addr) ((struct sockaddr*)(addr))
#define BACKLOG 8
static const uint16_t defaultport=8080;

enum exitcode{
    SOCK_ERROR=1,
    BIND_ERROR
};

class server
{
private:
    using task_t=std::function<void()>;
    using handle_t=std::function<std::string(std::string&)>;

    struct thread_data
    {
        int sockfd;
        server* self;
    };
    void echo_handle(int sockfd)
    {
        while(true)
        {
            char inbuffer[1024];
            int n=::read(sockfd,inbuffer,sizeof(inbuffer)-1);
            if(n>0)
            {
                inbuffer[n]='\0';
                LOG(INFO)<<"client say#"<<inbuffer;
                std::string recallmesg;
                recallmesg=inbuffer;
                recallmesg=_handle(recallmesg);
                ::write(sockfd,recallmesg.c_str(),recallmesg.size());
            }
            else if(n==0)
            {
                LOG(INFO)<<"client:"<<sockfd<<"is quit";
                ::close(sockfd);
                break;
            }
            else
            {
                LOG(ERROR)<<"read error";
                ::close(sockfd);
                break;
            }
        }
    }
public:
    server(handle_t handle,uint16_t port=defaultport):_handle(handle),_port(port)
    {}
    void InitServer()
    {
        //创建tcpsocket
        _listenfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if(_listenfd==-1)
        {
            LOG(FATAL)<<strerror(errno);
            DIE(SOCK_ERROR);
        }
        LOG(INFO)<<"SOCKET create successful";

        //初始化server socket并bind
        struct sockaddr_in server_sock;
        memset((void*)&server_sock,0,sizeof(server_sock));
        server_sock.sin_family=AF_INET;
        server_sock.sin_port=htons(_port);
        server_sock.sin_addr.s_addr=INADDR_ANY;

        int n=::bind(_listenfd,CONV(&server_sock),sizeof(server_sock));
        if(n==-1)
        {
            LOG(FATAL)<<strerror(errno);
            DIE(BIND_ERROR);
        }
        LOG(INFO)<<"bind successful";

        //打开监听模式
        n=listen(_listenfd,BACKLOG);
        if(n==-1)
        {
            LOG(ERROR)<<strerror(errno);
        }
        LOG(INFO)<<"listen successful";
        threadpoolmodule::threadpool<task_t>::GetInstance()->start();
    }
    static void* threadhandle(void* arg)
    {
        thread_data* t_data=(thread_data*) arg;
        t_data->self->echo_handle(t_data->sockfd);

        return nullptr;
    }
    void start()
    {
        //与发送信息的主机进行连接
        while(true)
        {
            struct sockaddr_in client_sock;
            socklen_t len=sizeof(client_sock);
            int sockfd=::accept(_listenfd,CONV(&client_sock),&len);
            if(sockfd==-1)
            {
                LOG(ERROR)<<strerror(errno);
                ::sleep(1);
                continue;
            }
            inetaddr client(client_sock);
            LOG(INFO)<<"client :"<<client.addr()<<"is conneted";
            
            //echo_handle(sockfd);
            //多进程版本 version1
            // int id=fork();
            // if(id==0)   //子进程执行
            // {
            //     ::close(_listenfd);
            //     if(fork()==0)
            //     {   //避免僵尸进程，当然也可以通过忽略sigchild的方式实现
            //         echo_handle(sockfd);
            //     }
            //     exit(0);
            // }
            // if(id<0)
            // {
            //     LOG(ERROR)<<"fork error"<<strerror(errno);
            // }
            // ::close(sockfd);
            // ::waitpid(id,nullptr,0);
            
            // //多线程版本————version2
            // pthread_t tid;
            // struct thread_data* t_ptr=new thread_data();
            // t_ptr->self=this;
            // t_ptr->sockfd=sockfd;
            // pthread_create(&tid,nullptr,threadhandle,(void*)t_ptr);
            // pthread_detach(tid);//将子线程设定为分离模式，这样就不需要回收线程了。

            //线程池版本-vesion3
            task_t func=std::bind(&server::echo_handle,this,sockfd);
            threadpoolmodule::threadpool<task_t>::GetInstance()->equeue(func);
        }
    }
    ~server()
    {}
private:
    uint16_t _port;
    int _listenfd;
    handle_t _handle;
};